/*
 @Name: treegrid插件
 @Author: ray
 @License: MIT
*/
; rayui.define(["jqlibs", "layer"], function (exports, undef) {
    "use strict";

    var $ = rayui.$,
        win = window,
        doc = document,
        plugName = "treegrid",
        layer = rayui.layer,
        dataCache = {
            tables: {},
            datas: {},
            cols: {},
            jqobjs: {}
        }, tableindex = 0, scrollGap = {}, $win = $(win), timer = null;
    $win.resize(function () {
        if (timer != null) clearTimeout(timer);
        timer = setTimeout(function () {
            timer = null;
            for (var t in dataCache.tables) {
                var that = dataCache.tables[t],
                    data = dataCache.datas[that.tableIndex];
                if (!data || data.length === 0) continue;
                DealClass.utils.modifyStyle.call(that);
            }
        }, 20);
    });

    var DealClass = function (table, option) {
        this.elem = table;
        this.tableIndex = tableindex;
        this.options = $.extend(true, {}, DealClass.option, option);
        //初始化
        DealClass.utils.init.call(this);
        return this;
    };
    //可被外部全局配置
    DealClass.option = {
        version: "1.1",
        fieldName: 'name',//树形菜单列
        fieldChildren: 'children',//数据子节点名称
        nowrap: true,//是否自动换行，默认不换行
        spread: false, //默认折叠
        icon: true,//是否显示图标
        minHeight: 80,//表格最小高度
        bgColors: false,//是否含有背景色
        initOnly: false,//只进行初始化，不请求数据
        loading: true, //请求数据时，是否显示loading
        cellMinWidth: 60, //所有单元格默认最小宽度
        animSpeed: 300//动画执行时间
    };

    var serialnum = 0;
    function getNum() {
        return serialnum++;
    }

    DealClass.utils = {
        //只运行一次
        initDefault: function () {
            //计算浏览横向滚动条的高度和竖向滚动条的宽度
            var $div = $("<div/>").appendTo($("body"));
            $div.width(100).height(100).css("overflow", "scroll");
            var elem = $div[0];
            scrollGap.width = elem.offsetHeight - elem.clientHeight;
            scrollGap.height = elem.offsetWidth - elem.clientWidth;
            $div.remove();
        },
        init: function () {
            var that = this,
                $t = $(this.elem),
                options = that.options;

            if (options.data && options.data instanceof Array)
                dataCache.datas[that.tableIndex] = options.data;
            else
                dataCache.datas[that.tableIndex] = [];

            var cols = dataCache.cols[that.tableIndex] = [];
            options.colsCount = 0;
            options.autoColNums = 0;
            options.minWidth = 0;
            options.autoCols = {};

            var cellcss = options.cellcss = {}, othercss = {},
                tableHead = (function () {
                    var str = [];
                    str.push('<table class="raytable-head"><thead>');
                    $(options.cols).each(function (a1, list) {
                        str.push('<tr>');
                        $(list).each(function (a, b) {
                            //表头和数据共有样式
                            var cellclass = "raytable-cell-" + that.tableIndex + "-" + (b.field ? b.field : getNum());
                            var curCellCss = cellcss[cellclass] = {};
                            //表头特有样式
                            var headclass = "raytable-cell-head-" + that.tableIndex + "-" + (b.field ? b.field : getNum());
                            var curheadCellCss = othercss[headclass] = {};
                            //数据特有样式
                            var curDataCellCss;
                            if (b.field) {
                                var dataclass = "raytable-cell-data-" + that.tableIndex + "-" + (b.field ? b.field : getNum());
                                curDataCellCss = othercss[dataclass] = {};
                            }

                            b.field && cols.push(b);
                            //计算css样式宽度
                            if (!b.hidden && b.field) {
                                if (b.width) {
                                    if (/^\d+$/.test(b.width)) {
                                        curCellCss.width = b.width + "px";
                                        curCellCss["min-width"] = Math.min(options.cellMinWidth, b.width) + "px";
                                        options.minWidth += b.width;
                                    } else if (/^\d+%$/.test(b.width) || b.width === "*") {
                                        options.widthType = true;
                                        curCellCss.width = b.width;
                                        curCellCss["min-width"] = options.cellMinWidth + "px";
                                        options.minWidth += options.cellMinWidth;
                                    }
                                } else {
                                    var minW = b.minWidth || options.cellMinWidth;
                                    curCellCss["min-width"] = minW + "px";
                                    options.minWidth += minW;
                                    options.autoCols[b.field] = {};
                                    options.autoCols[b.field].minWidth = minW;
                                    options.autoColNums++;
                                }
                                options.colsCount++;
                            }

                            b.align && (curCellCss["text-align"] = b.align);
                            //表头特有样式
                            b.style && (function () {
                                for (var c in b.style)
                                    curheadCellCss[c] = b.style[c];
                            })();
                            //数据特有样式
                            (b.field && b.dataStyle) && (function () {
                                for (var c in b.dataStyle)
                                    curDataCellCss[c] = b.dataStyle[c];
                            })();

                            str.push('<th class="' + cellclass);
                            //是否可拖拽，因为动态隐藏滚动条问题，固定列不支持拖拽宽度，暂时
                            str.push(b.field ? (b.resize ? " raytable-cell-resize" : "") : "");
                            str.push(b.style ? ' ' + headclass : '');
                            str.push(b.hidden ? ' hidden' : '');
                            str.push(options.nowrap ? ' raytable-nowrap' : '');
                            str.push('"');//class结束
                            str.push(b.colspan ? ' colspan=' + b.colspan : '');
                            str.push(b.rowspan ? ' rowspan=' + b.rowspan : '');
                            str.push(b.field ? ' data-field="' + b.field + '"' : '');
                            str.push(b.islink ? ' islink' : '');
                            str.push('>');//th前半开

                            //内容
                            var thContent = b.title === undef ? "" : b.title;

                            str.push(options.nowrap ? '<div class="raytable-nowrap ' + cellclass + ' ' + headclass + '">' + thContent + '</div>' : thContent);
                            str.push('</th>');
                        });
                        str.push("</tr>");
                    });

                    str.push("</thead></table>");

                    return str.join('');
                })(),

                tablebody = '<table class="raytable-body ' + (options.bgColors ? "treegrid-body" : "") + '" iteration=0><tbody></tbody></table>',

                tableMain = [
                    '<div class="raytable-box" style="',
                    'min-height:' + options.minHeight + 'px',
                    options.width ? ';width:' + options.width + 'px' : '',
                    '"',//end style
                    options.skin ? ' skin="' + options.skin + '"' : '',
                    '>',
                    '<div class="raytable-head-boxmain">',
                    '<div class="raytable-head-box">',
                    tableHead,
                    '</div>',
                    '</div>',//end raytable-head-boxmain
                    '<div class="raytable-body-boxmain">',
                    '<div class="raytable-body-box" scroll-left=1>',
                    tablebody,
                    '</div>',
                    '</div>',//end raytable-body-boxmain
                    //添加补丁
                    (function () {
                        var ss = [], count = options.cols.length;
                        ss.push('<div class="raytable-fixed-amend hidden">');
                        while (count-- > 0)
                            ss.push("<div/>");
                        ss.push("</div>");
                        return ss.join('');
                    })(),
                    '<div class="raytable-style">',
                    '</div>',
                    '<style>',
                    (function () {
                        var ss = [], isempty;
                        //这里只写其他样式，cell共有样式需要在首次初始化数据添加
                        for (var css in othercss) {
                            isempty = true;
                            for (var key in othercss[css]) {
                                if (isempty) {
                                    ss.push("." + css + "{");
                                    isempty = false;
                                }
                                ss.push(key + ":" + othercss[css][key] + ";");
                            }
                            if (!isempty)
                                ss.push("}");
                        }
                        //table层级背景颜色
                        if ($.isArray(options.bgColors)) {
                            var i = 0, tmpCount = options.bgColors.length;
                            for (; i < tmpCount; i++) {
                                ss.push('.treegrid-body[iteration="' + i + '"] > tbody > tr[data-index] {');
                                ss.push('background-color: ' + options.bgColors[i] + ';');
                                ss.push('}');
                            }
                        }

                        return ss.join('');
                    })(),
                    '</style>',
                    '</div>'
                ].join('');

            $t.after(tableMain);

            //提前设定选择器
            DealClass.utils.jqSelector.call(that);

            //没有写url，认为是本地分页
            if (options.url) {
                DealClass.utils.initHeight.call(that);
                //ajax请求数据
                DealClass.utils.ajaxData.call(that);
            } else {
                DealClass.utils.onRecvData.call(that);
            }
        },
        jqSelector: function () {
            var that = this;

            var jqobjs = dataCache.jqobjs[that.tableIndex] = {};
            jqobjs.tb_box = $(this.elem).next("div.raytable-box");
            //thead
            jqobjs.tb_head_boxmain = jqobjs.tb_box.find("div.raytable-head-boxmain");
            jqobjs.tb_head_box = jqobjs.tb_head_boxmain.find("div.raytable-head-box");
            jqobjs.tb_head = jqobjs.tb_head_box.find(">table");
            //tbody
            jqobjs.tb_body_boxmain = jqobjs.tb_box.find("div.raytable-body-boxmain");
            jqobjs.tb_body_box = jqobjs.tb_body_boxmain.find("div.raytable-body-box");
            jqobjs.tb_body = jqobjs.tb_body_box.find(">table");
            //补丁条
            jqobjs.tb_amend = jqobjs.tb_box.find(">.raytable-fixed-amend");
            //其他
            jqobjs.tb_head_body = jqobjs.tb_box.find("div.raytable-head-boxmain>div.raytable-head-box>table,div.raytable-body-boxmain>div.raytable-body-box>table");
            //css
            jqobjs.div_style = jqobjs.tb_box.find("div.raytable-style");
        },
        onRecvData: function () {
            var that = this,
                options = that.options;

            if (options.initComplete == undef) {
                options.initComplete = true;

                //设置样式
                var jqobjs = dataCache.jqobjs[that.tableIndex];

                //设置表格法最小宽度
                options.minWidth += options.colsCount;
                jqobjs.tb_head_body.css("min-width", options.minWidth + "px");

                //顺序不能变
                DealClass.utils.renderData.call(that);
                DealClass.utils.initStyle.call(that);

                DealClass.utils.addEvents.call(that);
            } else {
                DealClass.utils.renderData.call(that);
            }
            //渲染之前
            typeof options.onBeforeRenderStyle === "function" && options.onBeforeRenderStyle();
            //修改样式
            DealClass.utils.modifyStyle.call(that);
            //所有处理完毕
            typeof options.onComplete === "function" && options.onComplete();

        },
        ajaxData: function () {
            var that = this,
                options = that.options;

            DealClass.utils.showError.call(that, 0);
            if (options.initOnly) {
                options.initOnly = false;
                DealClass.utils.onRecvData.call(that);
                return;
            }

            DealClass.utils.loading.call(that, 1);
            var data = {};
            if (options.where)
                $.extend(data, options.where);
            $.ajax({
                type: options.method || "get",
                url: options.url,
                data: data,
                dataType: "json",
                beforeSend: function (xhr) {
                    if (typeof options.onAjaxBeforeSend === "function" &&
                        options.onAjaxBeforeSend.call(this, xhr) === false) {
                        xhr.abort();
                    }
                },
                success: function (result) {
                    //清除数据
                    DealClass.utils.clearData.call(that);
                    if (typeof options.onAjaxSuccess === "function") {
                        var retData = options.onAjaxSuccess.call(this, result);
                        if (retData == null || typeof retData !== "object") return;
                        result = retData;
                    }
                    //result数据格式：ret,msg,data
                    var code = result["ret"];
                    if (code !== 0) {
                        DealClass.utils.showError.call(that, (result["msg"] || "返回的数据状态异常"));
                    }
                    dataCache.datas[that.tableIndex] = result["data"] || [];
                    code === 0 && DealClass.utils.onRecvData.call(that);
                },
                error: function (xhr, textStatus, errorThrown) {
                    DealClass.utils.showError.call(that, "请求数据接口异常");
                    //所有处理完毕
                    typeof options.onAjaxError === "function" && options.onAjaxError.call(this, xhr, textStatus, errorThrown);
                },
                complete: function () {
                    DealClass.utils.loading.call(that, 0);
                }
            });
        },
        //type:0关闭1显示
        loading: function (type) {
            var that = this,
                options = that.options;
            if (!options.loading) return;

            var jqobjs = dataCache.jqobjs[that.tableIndex],
                $box = jqobjs.tb_box;

            if (type === 0) {
                $box.removeClass("temp-width-height");
                layer.close(options.layerLoadingIndex);
                return;
            }

            if (type === 1 && options.url) {
                $box.addClass("temp-width-height");
                options.layerLoadingIndex = layer.loading({
                    container: $box,
                    shadow: false
                });
            }
        },
        showError: function (msg) {
            var that = this,
                jqobjs = dataCache.jqobjs[that.tableIndex],
                $diverr = jqobjs.tb_body_box.find("div.raytable-msg");

            if (msg === 0) {
                $diverr.remove();
                return;
            }

            if ($diverr.length === 0)
                $diverr = $('<div class="raytable-msg"/>').appendTo(jqobjs.tb_body_box);

            $diverr.html(msg);
        },
        initStyle: function () {
            var that = this,
                options = that.options,
                jqobjs = dataCache.jqobjs[that.tableIndex];

            //设置共有样式，只初始化时运行一次
            if (options.cellcss) {
                var cellcss = options.cellcss;
                var ss = [], isempty, css;
                ss.push("<style>");
                //这里只写其他样式，cell共有样式需要在首次初始化数据添加
                for (css in cellcss) {
                    isempty = true;
                    for (var key in cellcss[css]) {
                        if (isempty) {
                            ss.push("." + css + "{");
                            isempty = false;
                        }
                        ss.push(key + ":" + cellcss[css][key] + ";");
                    }
                    if (!isempty)
                        ss.push("}");
                }
                ss.push("</style>");
                jqobjs.div_style.html(ss.join(''));
                //设置自动列样式
                isempty = true;
                for (var field in options.autoCols) {
                    isempty = false;
                    css = ".raytable-cell-" + that.tableIndex + "-" + field;
                    var style = DealClass.utils.getCssStyle.call(that, css);
                    options.autoCols[field].style = style;
                }
                isempty && (options.autoCols = undef);
                options.cellcss = undef;
            }
        },
        modifyStyle: function () {
            var that = this;
            DealClass.utils.fullHeight.call(that);
            DealClass.utils.fullWidth.call(that);
            DealClass.utils.modifyHead.call(that);
        },
        renderData: function () {
            var that = this,
                jqobjs = dataCache.jqobjs[that.tableIndex],
                $tbody = jqobjs.tb_body.find(">tbody"),
                options = that.options,
                data = DealClass.utils.getData.call(that);

            //清除数据
            DealClass.utils.clearData.call(that);
            if (data.length === 0) {
                DealClass.utils.showError.call(that, "无数据");
                return;
            }

            //添加数据
            var cols = dataCache.cols[that.tableIndex],
                innerTable = '<table class="innertable ' + (options.bgColors ? "treegrid-body" : "") + '"><tbody></tbody></table>';

            var addRow = function (data, $parent, iteration, preindex) {
                preindex = preindex || "";
                $(data).each(function (a, b) {
                    var trs = [],
                        hasChildren = b.hasOwnProperty(options.fieldChildren) && b[options.fieldChildren].length > 0,
                        spread = (b.spread === undef ? options.spread : b.spread);//默认折叠

                    //添加数据前
                    typeof options.onBeforeAddRow === "function" && options.onBeforeAddRow(a, b);
                    trs.push('<tr data-index=[' + preindex + a + ']');
                    trs.push(' class="');
                    trs.push(spread ? ' tree-spread' : '');
                    trs.push('"');//end class
                    trs.push('>');

                    $.each(cols, function (c, opt) {
                        var td = [],
                            field = opt.field,
                            cellCss = 'raytable-cell-' + that.tableIndex + '-' + field,
                            cellDataCss = 'raytable-cell-data-' + that.tableIndex + '-' + field;

                        td.push('<td data-field="' + field + '"');
                        td.push(' class="' + cellCss);
                        td.push(opt.hidden ? ' hidden' : '');
                        td.push(options.nowrap ? ' raytable-nowrap' : ' ' + cellDataCss);
                        options.fieldName === field && td.push(' rayui-treegrid-treefield');
                        td.push('"');//end class
                        td.push(opt.islink ? ' islink' : '');
                        td.push('>');

                        var value;
                        if (typeof opt.formatter === "function") {
                            //formatter函数
                            value = opt.formatter(b[field], b, a);
                        } else {
                            value = b[field];
                            if (opt.dataType === "html" && value !== undef && value !== '')
                                value = value.replace(/[<>&"]/g, function (c) { return { '<': '&lt;', '>': '&gt;', '&': '&amp;', '"': '&quot;' }[c]; });
                        }
                        if (value === undef || value === null || value === '') value = "&nbsp;";

                        td.push(options.nowrap ? '<div class="raytable-nowrap ' + cellCss + ' ' + cellDataCss + '">' : '');

                        //如果是fieldName项需要添加折叠箭头和图标
                        if (options.fieldName === field) {
                            for (var i = 0; i < iteration; i++) {
                                td.push('<span class="tree-hit treegrid-expand"></span>');
                            }
                            if (hasChildren) {
                                td.push('<span class="tree-hit btn-treespread"><i class="ra ra-collapsed"></i></span>');
                                //文件夹
                                options.icon && td.push('<span class="tree-hit"><i class="ra ra-folder-close"></i></span>');
                            } else {
                                td.push('<span class="tree-hit treegrid-expand"></span>');
                                //文件
                                options.icon && td.push('<span class="tree-hit"><i class="ra ra-file"></i></span>');
                            }
                        }
                        td.push('<span class="tree-title">' + value + '</span>');
                        options.nowrap && td.push('</div>');
                        td.push('</td>');

                        var strTmp = td.join('');
                        trs.push(strTmp);
                    });

                    trs.push("</tr>");
                    var strHtml = trs.join('');
                    var $tr = $("" + strHtml);
                    $tr.appendTo($parent);

                    //添加数据后
                    typeof options.onAddRow === "function" && options.onAddRow(a, $tr, b);

                    if (hasChildren) {
                        //主table
                        var $innerTable = $(innerTable),
                            $innerTbody = $innerTable.find("tbody"),
                            hiddenClass = spread ? "" : "hidden",
                            $newtr = $('<tr class="' + hiddenClass + '"><td class="rayui-treegrid-innertd" colspan="' + cols.length + '"><div class="innertable-box ' + hiddenClass + '"></div></td></tr>');
                        $innerTable.attr("iteration", iteration + 1).appendTo($newtr.find("div"));
                        $newtr.appendTo($parent);

                        addRow(b[options.fieldChildren], $innerTbody, iteration + 1, preindex + a + ",");
                    }
                });
            }

            addRow(data, $tbody, 0);

            data = null;
        },
        initHeight: function () {
            var that = this,
                $t = $(this.elem),
                options = that.options,
                jqobjs = dataCache.jqobjs[that.tableIndex],
                $theaddiv = jqobjs.tb_head_box,
                $tbodydiv = jqobjs.tb_body_box,
                fullHeightGap;

            !options.heightSetting && (options.heightSetting = options.height);

            if (/^full-\d+$/.test(options.heightSetting)) {//full-差距值
                fullHeightGap = options.heightSetting.split('-')[1];
                options.height = $win.height() - fullHeightGap;
            } else if (/^top-\d+$/.test(options.heightSetting)) {//top-差距值
                fullHeightGap = $t.offset().top;
                fullHeightGap += parseInt(options.heightSetting.split('-')[1]);
                options.height = $win.height() - fullHeightGap;
            } else if (/^sel-[#|\.][\w]+-\d+$/.test(options.heightSetting)) { //sel-id序列-差距值
                fullHeightGap = $t.offset().top;
                var list = options.heightSetting.split('-');
                $("" + list[1]).each(function () {
                    fullHeightGap += $(this).outerHeight();
                });
                if (list.length === 3) fullHeightGap += parseInt(list[2]);
                options.height = $win.height() - fullHeightGap;
            }

            //最终高度不能小于最小高度
            if (options.height < options.minHeight) options.height = options.minHeight;
            //数据高度-head-2px(raytable-box上下各1px border)
            var tmpH = options.height - $theaddiv.outerHeight() - 2;
            $tbodydiv.outerHeight(tmpH);//数据表格设置高度
        },
        fullHeight: function () {
            //计算高
            var that = this,
                options = that.options,
                jqobjs = dataCache.jqobjs[that.tableIndex],
                $tbodydiv = jqobjs.tb_body_box;

            //如果设置的是固定高度，则无需再设置了，ajax时initHeight方法会调用两遍
            if (!/^\d+$/.test(options.heightSetting)) DealClass.utils.initHeight.call(that);

            //数据高度大于数据box高度时，body最后一行去除下边框
            var $tables = jqobjs.tb_box.find(".raytable-body"),
                lastTrs = $tables.find("tr:visible:last");

            $tables.find("tr.last").removeClass("last");
            if ($tbodydiv.find(".raytable-body").outerHeight() >= $tbodydiv.outerHeight()) {
                lastTrs.addClass("last");
            }
        },
        //自适应宽度以数据宽度为准
        fullWidth: function () {
            var that = this,
                options = that.options,
                jqobjs = dataCache.jqobjs[that.tableIndex],
                $tb_data_first_tr = jqobjs.tb_body.find("tr:first"),
                $tbodydiv = jqobjs.tb_body_box,
                tbodydiv = $tbodydiv[0];

            //有自适应列时动态修改表头宽度
            if (options.autoCols && !options.resized) {
                var field, w;
                //必须，为了自适应数据宽度
                for (field in options.autoCols) {
                    options.autoCols[field].style.style.width = "";
                }

                //如果table小于div宽度就100%
                tbodydiv.clientWidth > options.minWidth && (jqobjs.tb_head_body.css("width", "100%"));

                if (!options.nowrap) {
                    //允许换行，使用table的自适应宽度
                    for (field in options.autoCols) {
                        //需要减去右边框1px，否则总是出现横向滚动条，不要使用width函数
                        w = $tb_data_first_tr.find("td[data-field=" + field + "]").outerWidth();
                        options.autoCols[field].style.style.width = w - 1 + "px";
                    }
                } else {
                    //不允许换行
                    var obj, aver = 0;
                    if (tbodydiv.clientWidth > options.minWidth) {
                        var widthGap = tbodydiv.clientWidth - options.minWidth;
                        aver = Math.floor(widthGap / options.autoColNums);
                    }
                    for (field in options.autoCols) {
                        obj = options.autoCols[field];
                        obj.style.style.width = obj.minWidth + aver + "px";
                    }
                }
                //修正头部滚动条
                jqobjs.tb_head_box.scrollLeft($tbodydiv.scrollLeft());
            }

            //百分比宽度
            if (options.widthType && !options.resized) {
                var cols = dataCache.cols[that.tableIndex],
                    totalWidth = jqobjs.tb_head_box.width() - cols.length,
                    surplus = totalWidth, fieldStarCss, ww = 0;
                $.each(cols, function (c, opt) {
                    var field = opt.field,
                        cellClass = '.raytable-cell-' + that.tableIndex + '-' + field,
                        cellCss = DealClass.utils.getCssStyle.call(that, cellClass);
                    if (opt.width === "*") {
                        fieldStarCss = cellCss;
                        return true;
                    }
                    var percent = ("" + opt.width).replace("%", ""),
                        width = totalWidth / 100 * (parseFloat(percent));

                    width = Math.floor(width);//解决那零点几导致的横向滚动条
                    cellCss.style.width = width + "px";
                    if (width < options.cellMinWidth) cellCss.style["min-width"] = width + "px";
                    surplus -= width;
                    ww += width;
                    return true;
                });
                if (fieldStarCss) {
                    fieldStarCss.style.width = surplus + "px";
                    if (surplus < options.cellMinWidth) fieldStarCss.style["min-width"] = surplus + "px";
                }
            }

            //判断是否去掉最后一列边框，数据宽度大于数据box可视宽度时去掉右边框
            jqobjs.tb_body.find("tr>td.last").removeClass("last");
            jqobjs.tb_head.find("tr>th.last").removeClass("last");
            var dataWidth = $tbodydiv.find(".raytable-body").outerWidth();
            if (dataWidth >= tbodydiv.clientWidth) {
                jqobjs.tb_body.find("tr").each(function () {
                    $(this).find("td:last").addClass("last");
                });
                jqobjs.tb_head.find("tr").each(function () {
                    $(this).find("th:last").addClass("last");
                });
            }

            /*判断显隐补丁
                        -------     有横向    无横向  正好无横向
                        有竖向       显示       隐藏        显示
                        无竖向       隐藏       隐藏        隐藏
                 正好无竖向       隐藏       隐藏        隐藏
            */
            if (dataWidth >= tbodydiv.clientWidth && tbodydiv.scrollHeight > tbodydiv.clientHeight) {
                //显示
                jqobjs.tb_amend.removeClass("hidden");
            } else {
                //隐藏
                jqobjs.tb_amend.addClass("hidden");
            }
        },
        //修改表头
        modifyHead: function () {
            var that = this,
                options = that.options,
                jqobjs = dataCache.jqobjs[that.tableIndex],
                $theaddiv = jqobjs.tb_head_box,
                $tbodydiv = jqobjs.tb_body_box,
                $tbhead = jqobjs.tb_head;

            var tbodydiv = $tbodydiv[0];
            if (tbodydiv.scrollHeight > tbodydiv.clientHeight) {
                //说明有竖向滚动条
                $theaddiv.css("margin-right", (scrollGap.width) + "px");
            } else {
                $theaddiv.css("margin-right", "0");
            }

            //补丁条的高度
            jqobjs.tb_amend.css("right", scrollGap.width - 49 + "px") //amend宽度50，减去自己的左边框1px
                .find("div").each(function (a) {
                    $(this).height($tbhead.find("tr:eq(" + a + ")").height() - 1);//下边框
                });
        },
        clearData: function () {
            var that = this,
                jqobjs = dataCache.jqobjs[that.tableIndex],
                $tbody = jqobjs.tb_body.find(">tbody");

            $tbody.html("");
        },
        deleteData: function (indexs) {
            var that = this,
                options = that.options,
                count = indexs.length,
                i = 1,
                datas = DealClass.utils.getData.call(that);

            if (count > 1) {
                var data = datas[indexs[0]];
                while (i < count - 1)
                    data = data[options.fieldChildren][indexs[i++]];
                data[options.fieldChildren].splice(indexs[count - 1], 1);
            } else {
                datas.splice(indexs[0], 1);
            }
        },
        spreadData: function (indexes, flag) {
            if (indexes.length === 0) return;
            var that = this,
                options = that.options,
                datas = DealClass.utils.getData.call(that),
                count = indexes.length,
                i = 1,
                data = datas[indexes[0]];
            //展开必须逐级都展开，关闭只关闭最后一级
            if (flag) data.spread = true;
            while (i < count) {
                data = data[options.fieldChildren][indexes[i++]];
                if (flag) data.spread = true;
            }
            if (!flag) data.spread = false;
        },
        reload: function (option) {
            option !== undef && $.extend(true, this.options, option);
            var that = this,
                options = that.options;

            if (options.url) {
                DealClass.utils.ajaxData.call(that);
            } else {
                DealClass.utils.onRecvData.call(that);
            }
        },
        getCssStyle: function (css) {
            var that = this,
                jqobjs = dataCache.jqobjs[that.tableIndex],
                style = jqobjs.div_style.find("style")[0],
                sheet = style.sheet || style.styleSheet,
                rules = sheet.cssRules || sheet.rules;

            var curCss;
            $(rules).each(function (a, rr) {
                if (css === rr.selectorText) {
                    curCss = rr;
                    return false;
                }
                return true;
            });
            //如果没有则添加一条，因为初始化的时候保证一定含有，所以这里没必要再添加了
            return curCss;
        },
        getData: function (indexes) {
            var that = this,
                options = that.options,
                datas = dataCache.datas[that.tableIndex];

            if (indexes === undef) return datas;
            var count = indexes.length,
                i = 1,
                data = datas[indexes[0]];
            while (i < count)
                data = data[options.fieldChildren][indexes[i++]];
            return data;
        },
        addEvents: function () {
            var that = this,
                dict = {},
                $doc = $(doc),
                $body = $('body'),
                jqobjs = dataCache.jqobjs[that.tableIndex],
                $thisAllTable = jqobjs.tb_head_body,
                $tbodydiv = jqobjs.tb_box.find("div.raytable-body-box"),
                options = that.options;

            //拖拽调整宽度
            jqobjs.tb_box.find(".raytable-head").on('mousemove.' + plugName, "th[class*=raytable-cell-resize]", function (e) {
                if (dict.resizeStart) return;
                var othis = $(this),
                    oLeft = othis.offset().left,
                    pLeft = e.clientX - oLeft;
                //是否处于拖拽允许区域
                dict.allowResize = othis.outerWidth() - pLeft <= 10;
                $body.css('cursor', (dict.allowResize ? 'col-resize' : ''));
            }).on('mouseleave.' + plugName, "th[class*=raytable-cell-resize]", function () {
                if (dict.resizeStart) return;
                $body.css('cursor', '');
            }).on('mousedown.' + plugName, "th[class*=raytable-cell-resize]", function (e) {
                if (dict.allowResize) {
                    e.preventDefault();
                    var $othis = $(this);
                    dict.elem = this;
                    dict.width = $othis.width();
                    dict.resizeStart = true; //开始拖拽

                    var thcss = ".raytable-cell-" + that.tableIndex + "-" + $(dict.elem).data("field");
                    dict.cssRule = DealClass.utils.getCssStyle.call(that, thcss);

                    var cssminWidth = parseFloat($othis.css("min-width").replace("px", ""));
                    dict.minWidth = cssminWidth === 0 ? options.cellMinWidth : cssminWidth;
                    dict.offset = e.clientX; //记录初始坐标
                    var tbone = $thisAllTable.eq(0);
                    //记录当前table宽度
                    dict.tb_width = tbone.outerWidth();
                    dict.tb_minwidth = parseFloat(tbone.css("min-width").replace("px", ""));
                }
            });

            //拖拽中
            $doc.on('mousemove.' + plugName, function (e) {
                if (dict.resizeStart) {
                    e.preventDefault();
                    if (dict.elem) {
                        options.resized = true;
                        var gap = e.clientX - dict.offset;
                        var setWidth = dict.width + gap;
                        if (setWidth > dict.minWidth) {
                            dict.cssRule.style.width = setWidth + "px";
                            var newTbW = dict.tb_width + gap;
                            //修改最小宽度和宽度
                            $thisAllTable.outerWidth(newTbW);
                            if (newTbW < dict.tb_minwidth)
                                $thisAllTable.css("min-width", newTbW + "px");
                            DealClass.utils.modifyStyle.call(that);
                        }
                    }
                }
            }).on('mouseup.' + plugName, function () {
                if (dict.resizeStart) {
                    dict = {};
                    $body.css('cursor', '');
                }
            });

            //行事件
            var tables = jqobjs.tb_box.find("div.raytable-body-box>table");
            if (tables.length > 1) {
                tables.on('mouseenter.' + plugName, "tr", function (e) {
                    tables.find("tr:eq(" + $(this).index() + ")").addClass("raytable-tr-hover");
                    e.stopPropagation();
                    e.preventDefault();
                }).on('mouseleave.' + plugName, "tr", function (e) {
                    tables.find("tr:eq(" + $(this).index() + ")").removeClass("raytable-tr-hover");
                    e.stopPropagation();
                    e.preventDefault();
                });
            }

            //横竖向滚动条，$tbodydiv有3个，数据、左固定、右固定
            var funcScrollTop = function () {
                if ($(this).attr("scroll-left") === "1") jqobjs.tb_head_box.scrollLeft($(this).scrollLeft());
                $tbodydiv.not(this).scrollTop($(this).scrollTop());
            }
            $tbodydiv.on('scroll.' + plugName, funcScrollTop);
            $tbodydiv.hover(function () {
                $tbodydiv.not(this).off("scroll.raytable", funcScrollTop);
            }, function () {
                //$tbodydiv.not(this).on('scroll.raytable', funcScrollTop);
                //不能使用上面代码，因为当删除数据导致div没有时，数据的div无法绑定事件
                $tbodydiv.off('scroll.' + plugName, funcScrollTop)
                    .on('scroll.' + plugName, funcScrollTop);
            });

            //折叠和展开
            $tbodydiv.on('click.' + plugName, '.btn-treespread', function (e) {
                var $tr = $(this).closest("tr"),
                    indexes = $tr.data("index"),
                    $trnext = $tr.next(),
                    $divbox = $trnext.find(">td>div.innertable-box"),
                    isSpread = $tr.hasClass("tree-spread"),
                    data;

                options.onExpanded &&
                    (data = (function () {
                        var datas = DealClass.utils.getData.call(that, indexes);
                        datas = $.extend({}, datas);
                        delete datas[options.fieldChildren];
                        return datas;
                    })());

                //折叠情况反馈到数据中
                DealClass.utils.spreadData.call(that, indexes, !isSpread);

                if (isSpread) {
                    //折叠
                    $divbox.slideUp(options.animSpeed, function () {
                        $tr.removeClass("tree-spread");
                        $trnext.addClass("hidden");
                        DealClass.utils.modifyStyle.call(that);
                        options.onExpanded && options.onExpanded.call($tr[0], data, $trnext, !isSpread);
                    });
                } else {
                    //展开
                    $tr.addClass("tree-spread");
                    $trnext.removeClass("hidden");
                    $divbox.slideDown(options.animSpeed, function () {
                        DealClass.utils.modifyStyle.call(that);
                        options.onExpanded && options.onExpanded.call($tr[0], data, $trnext, !isSpread);
                    });
                }
                e.stopPropagation();
            });

            //如果出现省略，则可查看更多
            jqobjs.tb_box.on('click.' + plugName + 'Show', 'td.raytable-nowrap:not("[islink]")', function () {
                var obj = $(this).find("div")[0] || this;
                if (obj.scrollWidth > $(obj).outerWidth()) {
                    var $p = $(".raytable-tips");
                    if ($p.length === 0) {
                        $p = $('<div class="raytable-tips"><div class="raytable-tips-content"></div></div>').appendTo($body);
                        $('<i class="raytable-tips-close"></i>')
                            .appendTo($p)
                            .click(function () {
                                $p.remove();
                            });
                    }

                    var $content = $p.find(".raytable-tips-content");
                    $content.html($(obj).html());
                    //$content.append($(obj).find("span.tree-title").clone());

                    //计算left、top
                    var cwidth = $win.width(),
                        offset = $(this).offset(),
                        left, top = offset.top - 1,
                        width = $p.outerWidth();

                    width > 500 && (width = 500);
                    if (offset.left + width < cwidth) {
                        left = offset.left;
                    } else {
                        var tmpW = offset.left + $(obj).outerWidth();
                        if (width > tmpW)
                            width = tmpW;
                        left = tmpW - width;
                    }

                    $p.css({
                        width: width + "px",
                        top: top + "px",
                        left: left + "px"
                    });

                }
            });

        },
        on: function (event, func) {
            if (typeof event !== "string" || typeof func !== "function") return;
            var that = this,
                options = that.options,
                jqobjs = dataCache.jqobjs[that.tableIndex],
                crtObj = function (indexes, $tr) {
                    var data = (function () {
                        var datas = DealClass.utils.getData.call(that, indexes);
                        datas = $.extend({}, datas);
                        delete datas[options.fieldChildren];
                        return datas;
                    })(),
                        $datatr = {
                            index: indexes,
                            data: data,
                            tr: $tr,
                            del: function () {
                                //删除本地数据
                                DealClass.utils.deleteData.call(that, indexes);
                                //本地重新渲染数据
                                DealClass.utils.onRecvData.call(that);
                            },
                            update: function () {
                                //更新本地数据
                                var pdata = DealClass.utils.getData.call(that, indexes);
                                $.extend(pdata, data);
                                //本地重新渲染数据
                                DealClass.utils.onRecvData.call(that);
                            }
                        };
                    return $datatr;
                };

            switch (event) {
                case "click":
                    jqobjs.tb_box.on('click.btn.' + plugName, '.raytable-body td[data-field^=opt] *[ray-event]', function () {
                        var evt = $(this).attr("ray-event"),
                            $tr = $(this).closest("tr"),
                            indexes = $tr.data("index");
                        func.call(this, evt, crtObj(indexes, $tr));
                    });
                    break;
                //swich点击事件
                case "swich":
                    rayui.swich && rayui.swich.on("swich", function (obj) {
                        //this为渲染的swich，obj包含： event,elem,value,title
                        var $tr = $(this).closest("tr"),
                            indexes = $tr.data("index"),
                            $datatr = $.extend(crtObj(indexes, $tr), obj);
                        return func.call(this, obj.event, $datatr);
                    }, jqobjs.tb_box);
                    break;
                //以下事件写相应属性事件也是可以的
                //折叠展开行
                case "expanded": options.onExpanded = func; break;
            }
        }
    }

    DealClass.prototype = {
        on: function (event, callback) {
            DealClass.utils.on.call(this, event, callback);
            return this;
        },
        getData: function () {
            return DealClass.utils.getData.call(this);
        },
        getDataByIndexs: function (indexes) {
            var that = this, options = that.options;
            var datas = DealClass.utils.getData.call(that, indexes);
            datas = $.extend({}, datas);
            delete datas[options.fieldChildren];
            return datas;
        },
        reload: function (option) {
            DealClass.utils.reload.call(this, option);
            return this;
        }
    };

    var treegrid = {
        options: DealClass.option,
        render: function (option) {
            scrollGap.width || function () {
                //可以在这里加载css
                DealClass.utils.initDefault();
            }();
            var obj = option.elem;
            if ($(obj).length === 0) return "DOM对象不存在";
            var classObj = new DealClass(obj, option);
            dataCache.tables[tableindex++] = classObj;
            return classObj;
        }
    }

    exports(plugName, treegrid);
}, rayui.jsAsync());
